// 扩展2. typename和class的区别
/**
 * 在 C++ Template 中很多地方都用到了 typename 与 class 这两个关键字，而且好像可以替换，是不是这两个关键字完全一样呢?

 * 相信学习 C++ 的人对 class 这个关键字都非常明白，class 用于定义类，在模板引入 c++ 后，最初定义模板的方法为：

        template<class T>......

 * 这里 class 关键字表明T是一个类型，后来为了避免 class 在这两个地方的使用可能给人带来混淆，所以引入了 typename 这个关键字，它的作用同 class 一样表明后面的符号为一个类型，这样在定义模板的时候就可以使用下面的方式了：

        template<typename T>......
 * 在模板定义语法中关键字 class 与 typename 的作用完全一样。

 * typename 难道仅仅在模板定义中起作用吗？其实不是这样，typename 另外一个作用为：使用嵌套依赖类型(nested depended name)，如下所示：

        typedef typename T::LengthType LengthType; 
  
  * 这个时候 typename 的作用就是告诉 c++ 编译器，typename 后面的字符串为一个类型名称，而不是成员函数或者成员变量，这个时候如果前面没有 typename，编译器没有任何办法知道 T::LengthType 是一个类型还是一个成员名称(静态数据成员或者静态函数)，所以编译不能够通过。
*/

#include <iostream>
#define __mark 2

/**
 * #1 测试自定义类型 与变量重复
*/
#if 1 == __mark
class Test
{
public:
  typedef int mytype;
  // 不能重名
  int a = 1;
  void b()
  {
    std::cout << "mytype()..." << std::endl;
  }
};
int main(void)
{
  Test t;
  std::cout << "t.mytype : " << t.a << std::endl;
  t.b();
  Test::mytype c = 3; // 这样写它知道是变量类型
  std::cout << "c : " << c << std::endl;
  printf("--------------------end-------------------\n");
  return 0;
}
/**
 * #2 嵌套依赖类型
*/
#elif 2 == __mark
class MyArray
{
public:
  typedef int lengthType;
  lengthType length()
  {
    int len = 3;
    return len;
  }
};

template <class T>
void test(T &obj)
{
  // typedef T::lengthType lengthType; // error: need 'typename' before 'T::lengthType' because 'T' is a dependent scope
  typedef typename T::lengthType lengthType;
  lengthType len = obj.length();//  error: passing 'const MyArray' as 'this' argument discards qualifiers [-fpermissive]   
  std::cout << "len : " << len << std::endl;
}
int main(void)
{
  MyArray arr;
  test(arr);
  printf("--------------------end-------------------\n");
  return 0;
}
#endif